import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Scanner;

/**
 * This pass get all lines into a queue,discard comments,get all symbols stored
 * ,values not set yet,get seg name stored, get starting location stored.
 * 
 * @author LK
 *
 */
public class Pass1 {

	/**
	 * This field store the name of the input file.
	 */
	private static String fileName;



	// ------------------public methods-----------------------------
	public static void readLines(String file) throws FileNotFoundException,AssembleException {
		// store the input file name;
		fileName = file;

		FileReader reader = new FileReader(fileName);
		Scanner in = new Scanner(reader);

		// keep tracking of line number.
		int lineNum = 1;


		while (in.hasNext()) {
			String line = in.nextLine();
			line = Utilities.removeComment(line);
			
			if(line.length()>0) {//not a empty line or a comment line.
				
				//represent current line of source code in a way that can be stored in to program memory(Lines);
				Instruction instr = new Instruction(line,lineNum);
				
				//get seg name and starting location.
				if(instr.getOps().equals(".ORIG")) {
					
					//flag source code has .ORIG at beginning.
					if(Lines.size() == 0) {
						Lines.setORIG();
					}
					
					//store segment name
					Lines.stSegName(instr.getSymb());
					//store seg name into ENT table                    
					ENTTable.add(instr.getSymb(), lineNum); //TODO added for lab3.
					//store staring location.
					Lines.stStartingLoc(Integer.parseInt(instr.getOperand()[0].substring(1), 16));
					//set location counter
					Lines.setLC(Lines.getStartingLoc());
				}
				
				
				//store symbol:value.
				if(instr.hasSymb()) {
					String symb = instr.getSymb();
					
					//TODO updated for lab3,update UG and PG if necessary.
                    if(instr.getOps().equals(".EXT")||instr.getOps().equals(".ENT")) {
                            throw new AssembleException(17,lineNum,instr.getOps());
                    }
                    //TODO end of updated in this segment.
					
					//check if any whitespace inside symbol.
					if(symb.contains(" ")) {
						throw new AssembleException(14,instr.getLineNum(),instr.getSymb());
					}
					
					//check if a symbol is falsely named with 'R' or 'x' as first character.
					if(symb.charAt(0)=='R' || symb.charAt(0)=='x') {
						throw new AssembleException(6,instr.getLineNum(),symb);
					}
					
					
					if(!instr.getOps().equals(".ORIG") && !instr.getOps().equals(".EQU")) {
						//store and check multiple definition of symbols.
							if(SymbTable.stSym(symb, Lines.getLC())==0) {
								throw(new AssembleException(2,lineNum,symb));
							}
					}else if(instr.getOps().equals(".EQU")) {
						int val = 0;
						if (instr.getOperand()[0].charAt(0) == '#') {
							val = Integer.parseInt(instr.getOperand()[0].substring(1));
						}else if(instr.getOperand()[0].charAt(0) == 'x'){
							val = Integer.parseInt(instr.getOperand()[0].substring(1),16);
						}else {
							if(SymbTable.getVal(instr.getOperand()[0]) == null) {
								throw new AssembleException(8,instr.getLineNum(),instr.getOperand()[0]);
							}
						}
						//store and check multiple definition of symbols.
						if(SymbTable.stSym(symb, val)==0) {
							throw(new AssembleException(2,lineNum,symb));
						}
						SymbTable.addToConsLst(symb);
					}
					
				}
				
				if(instr.getOps().equals(".BLKW")) {
					char firstCh = instr.getOperand()[0].charAt(0);
					if(firstCh != 'x' && firstCh != '#') {
						//check forward referencing
						if (SymbTable.getVal(instr.getOperand()[0]) == null) {
							throw new AssembleException(8,instr.getLineNum(),instr.getOperand()[0]);
						}
					}
				}
				
				//store literals.
				if(instr.getOps().equals("LD") && instr.getOperand()[1].charAt(0)=='='){
					int val = 0;
					if (instr.getOperand()[1].charAt(1) == '#') {
						val = Integer.parseInt(instr.getOperand()[1].substring(2));
					}else {
						val = Integer.parseInt(instr.getOperand()[1].substring(2),16);
					}
					LitTable.stLit(val);
				}
				
				
				if(!instr.getOps().equals(".END") && !instr.getOps().equals(".EQU")
						&& !instr.getOps().equals(".ORIG") && !instr.getOps().equals(".EXT")
                        && !instr.getOps().equals(".ENT")) {
					//get address associated with current line of source code.
					instr.setAddr(Lines.getLC());
				}
				//increment location counter.
				Lines.setLC(instr.memTaken());
				
				//store current line into program memory(Lines)
				Lines.add(instr);
				
				
			}
			lineNum++;
		}
		//check if no .END at end.
		if(!Lines.get(Lines.size()-1).getOps().equals(".END")) {
			throw new AssembleException(13);
		}
		
		//deal with literal values.
		LitTable.appendLit();
		
		//get segment size and store in program memory.
		Lines.calcSegSize();
		

	}

}
